<?php
namespace bee;

/**
 *
 * @author dzelenika
 *
 */
class eventDispatcher implements IeventDispatcher
{

  const DISPATCH_ONLY_REFISTERED = 0;
  const DISPATCH_ALL_FUNCTIONS = 1;
  const DISPATCH_ALL_METHODS = 2;

  const EVT_ENTER_SITE                  = 100;
  const EVT_START_REQUEST               = 200;

  const EVT_END_REQUEST                 = 9990;
  const EVT_LEAVE_SITE                  = 9999;

  private $event = array();
  private $object = array();
  private $dispatchProgress;
  private $dispatchLevel;

  use Tsingleton;

  private function construct()
  {
    $this->dispatchLevel = config::SYS_DISPATCH_LEVEL;// ::getInstance()->getSetting(bee\DISPATCH_LEVEL);
  }

  /**
   *
   * @return eventDispatcher
   */
  public static function getInstance()
  {
  	return static::__getInstance();
  }

  /**
   *
   * @return boolean Ambigous unknown>
   */
  private function getNextEventKey()
  {
    if(count($this->event) == 0)
    {
      return false;
    }

    $minKey = 0;
    foreach($this->event as $key => $value)
    {
      if($key < $minKey || !$minKey)
      {
        if(!$value["fired"])
        {
          $minKey = $key;
        }
      }
    }
    return $minKey;

  }

  /**
   *
   * @param
   *        $event
   * @param unknown $order
   * @return bool
   */
  public function registerEvent($event, $order)
  {
    if(isset($this->event[$order]))
    {
      throw new exception("Event order: $order for event $event allready registered", 6969);
    }
    if(($k=array_search($event, array_column($this->event, "event"))) === false)
    {
      $this->event[$order]["event"] = $event;
      $this->event[$order]["fired"] = false;
      return true;


    }
    throw new exception("Event $event allready registered", 6969);


  }

  /**
   *
   * @param unknown $object
   * @throws exception
   */
  public function registerObject($object)
  {
    if(!is_object($object))
    {
      throw new exception("Registered item is not an object " . print_r($object, true), 6969);
    }
    if(!isset($object->__withEvents))
    {
      throw new exception("Registered Object can't fire events: " . print_r($object, true), 6969);
    }
    echo "<br />dodajem " . print_r($object, true);
    if(!in_array($object, $this->object))
    {
      echo "<br />dodan " . print_r($object, true);
      $this->object[] = $object;
      foreach($object as $item)
      {
        if(is_object($item) && isset($item->__withEvents))
        {
          $this->registerObject($item);
        }
      }
    } else
    {
      // echo "ALLREADY IN DISPATH TABLE";
    }

  }

  /**
   *
   * @param unknown $event
   * @param string $args
   * @param string $singleDispatch
   * @return number
   */
  public function dispatchEvent($event, $args = array(), $singleDispatch = false)
  {

    echo "<br />dispatching: " . $event;
    $found = 0;
    echo "<br />" . print_r($this->event, true);

    if(in_array($event, $this->event) || (config::getInstance()->getSetting(config::SYS_DISPATCH_LEVEL) & static::DISPATCH_ALL_METHODS == static::DISPATCH_ALL_METHODS))
    {
      foreach($this->object as &$object)
      {
        if(method_exists($object, $event))
        { // echo "\n<br />AUTO OBJECT " . get_class($object);// . "\n<br />";
          $found++;
          $object->$event($args);
          if($singleDispatch) return $found;
        }
      }
    }

    if(in_array($event, $this->event) && (config::getInstance()->getSetting(DISPATCH_LEVEL) & static::DISPATCH_ALL_FUNCTIONS == static::DISPATCH_ALL_FUNCTIONS))
    {
      throw new exception("Event $event not registered", 6969);
    }

    if(function_exists($event))
    { //echo " AUTO FUNCTION " . get_class($object);
      $found++;
      call_user_func_array($event, $args);
      if($singleDispatch) return $found;
    }

    if($found == 0)
    {
    	throw new exception(xdebug_print_function_stack("No events fired for event $event "), 6969);
    }
    return $found;

  }

  private function dispatchEventByNumber($number, $args = array(), $singleDispatch = false)
  {
    echo "<br />dispatching: " . $number;
    $found = 0;
    echo "<br />" . print_r($this->event, true);

    if(isset($this->event[$number]) || (config::SYS_DISPATCH_LEVEL & static::DISPATCH_ALL_METHODS == static::DISPATCH_ALL_METHODS))
    {
      $event = $this->event[$number]["event"];
      foreach($this->object as &$object)
      {
        if(method_exists($object, $event))
        { // echo "\n<br />AUTO OBJECT " . get_class($object);// . "\n<br />";
          $found++;
          $object->$event($args);
          if($singleDispatch) return $found;
        }
      }
    }

    if(isset($this->event[$number]) || (config::SYS_DISPATCH_LEVEL & static::DISPATCH_ALL_FUNCTIONS == static::DISPATCH_ALL_FUNCTIONS))
    {
      $event = $this->event[$number]["event"];
      if(function_exists($event))
      {
        $found++;
        call_user_func_array($event, $args);
        if($singleDispatch) return $found;
      }
    } else
    {
    throw new exception("Event $event not registered", 6969);
    }


    if($found == 0)
    {
      throw new exception(xdebug_print_function_stack("No events fired for event $event "), 6969);
    }
    return $found;

  }

  public function dispatchNextEvent()
  {
    $evtKey = $this->getNextEventKey();

    if($evtKey)
    {

      echo "<br />dispatching: " . print_r($this->event[$evtKey], true);
      $this->dispatchEventByNumber($evtKey);// number)($this->event[$evtKey]["event"]);
      $this->event[$evtKey]["fired"] = true;
    }
    return $evtKey;
  }
}